#include <fstream>
#include <strstream>

#ifdef COMPRESSION
#include <boost/iostreams/filter/zlib.hpp>
#include <boost/iostreams/filtering_stream.hpp>
namespace io = boost::iostreams;
#endif

#include <windows.h>

#include "archive.h"
#include "path.h"
#include "io.h"
#include "system.h"

namespace
{
    void insert_variables(std::string &command)
    {
        std::string::size_type var = 0;
        for(;;)
        {
            var = command.find_first_of("%", var);
            if(var == std::string::npos)
                break;

            if(var + 1 == command.size())
                break;

            char ch = command[var + 1];
            std::string replacement;
            switch(ch)
            {
                case '%':
                {
                    replacement = "%";
                    break;
                }

                case 'w': case 'W':
                {
                    char buf[MAX_PATH];
                    GetCurrentDirectory(MAX_PATH, buf);
                    replacement = buf;
                    break;
                }

                default:
                    var++;
                    continue;
            }
            command.replace(var, 2, replacement);
            var += replacement.size();
        }
    }

    void run_program(std::string command, const std::string &dir)
    {
        PROCESS_INFORMATION process_info;
        STARTUPINFO startup_info = {sizeof(STARTUPINFO)};

        insert_variables(command);

        char *cmd_buf = new char [command.size() + 1];
        strcpy(cmd_buf, command.c_str());
        cmd_buf[command.size()] = 0;

        CreateProcess(
            0,
            cmd_buf,
            0,
            0,
            FALSE,
            0,
            0,
            dir.c_str(),
            &startup_info,
            &process_info
        );

        delete[] cmd_buf;

        WaitForSingleObject(process_info.hProcess, INFINITE);
    }
}

int WINAPI WinMain(HINSTANCE, HINSTANCE, LPSTR options, int)
{
    DWORD size;
    void *data = load_rcdata(size);

    char *char_data = reinterpret_cast<char *>(data);
    std::strstream stream(char_data, size, std::ios::in);

    #ifdef COMPRESSION
        char compress;
        stream.read(&compress, 1);

        io::filtering_stream<io::input> read;
        if (compress)
        {
            read.push(io::zlib_decompressor());
        }
        read.push(stream);
    #else
        std::strstream &read = stream;
    #endif

    std::string extract_path = temp_path();

    std::string command = read_archive(read, extract_path);
    command = extract_path + "\\" + command;

    if(strcmp(options, ""))
        command.append(" ").append(options);

    run_program(command, extract_path);
    recursive_delete(extract_path);
    return 0;
}
